package cool.taomu.toolkit.service.centre.kademlia

import com.google.auto.service.AutoService
import com.google.common.util.concurrent.RateLimiter
import com.google.inject.AbstractModule
import com.google.inject.Key
import com.google.inject.TypeLiteral
import com.google.inject.name.Names
import cool.taomu.toolkit.TaomuConfigure
import cool.taomu.toolkit.platform.inter.AbsPlatform
import cool.taomu.toolkit.platform.inter.IPlatform
import cool.taomu.toolkit.provider.RateLimiterProvider
import cool.taomu.toolkit.rpc.thrift.server.module.ThritfTHsHaServerModule
import cool.taomu.toolkit.rpc.thrift.server.service.TaomuThriftTHsHaServer
import cool.taomu.toolkit.service.centre.kademlia.module.ServiceCentreModule
import cool.taomu.toolkit.service.centre.kademlia.module.ServiceCentreProvider
import cool.taomu.toolkit.service.centre.kademlia.service.CheckPeerImpl
import cool.taomu.toolkit.service.centre.kademlia.service.CheckRemoteNode
import cool.taomu.toolkit.service.centre.kademlia.service.FindNodeServiceFunc
import cool.taomu.toolkit.service.centre.kademlia.service.FindServiceNodeService
import cool.taomu.toolkit.service.centre.kademlia.service.ICheckRemoteNode
import cool.taomu.toolkit.service.centre.kademlia.utils.ClientExec
import cool.taomu.toolkit.service.centre.kademlia.utils.KRoutingTableUtils
import cool.taomu.toolkit.service.centre.kademlia.utils.ResourceCollector
import cool.taomu.toolkit.service.kademlia.entity.FindNodeEntity
import cool.taomu.toolkit.service.kademlia.entity.FindServiceNodeEntity
import cool.taomu.toolkit.service.kademlia.entity.KPeerNode
import cool.taomu.toolkit.service.kademlia.service.ICheckPeer
import cool.taomu.toolkit.service.kademlia.service.KRoutingTable
import java.util.List
import java.util.function.Function
import org.apache.thrift.TProcessor
import org.slf4j.LoggerFactory

@AutoService(IPlatform)
class ServiceCentrePlugin extends AbsPlatform {

	val static LOG = LoggerFactory.getLogger(ServiceCentrePlugin);

	override note() {
		"Kademlia DHT 服务"
	}

	override packages() {
		"cool.taomu.toolkit.service.centre.kademlia.controller"
	}

	override module(TaomuConfigure config) {
		new AbstractModule() {
			override configure() {
				LOG.info("加载 Kademlia 配置")
				install(new ThritfTHsHaServerModule())
				install(new ServiceCentreModule())
				bind(RateLimiter).toProvider(RateLimiterProvider)
				bind(ICheckPeer).to(CheckPeerImpl).asEagerSingleton;
				bind(new TypeLiteral<Function<FindNodeEntity, List<KPeerNode>>>() {
				}).annotatedWith(Names.named("taomu.toolkit.kademlia.findNode")).to(FindNodeServiceFunc).asEagerSingleton;
				bind(new TypeLiteral<Function<FindServiceNodeEntity, List<KPeerNode>>>() {
				}).annotatedWith(Names.named("taomu.toolkit.kademlia.findServiceNode")).to(FindServiceNodeService).
					asEagerSingleton;
				bind(TProcessor).annotatedWith(Names.named("taomu.toolkit.kademlia.processor")).toProvider(ServiceCentreProvider)
				bind(ResourceCollector).asEagerSingleton
				bind(ClientExec)
				bind(ICheckRemoteNode).to(CheckRemoteNode).asEagerSingleton
			}
		}
	}

	override start() {
		val injecotr = this.context.injectorSupplier.get
		val server = injecotr.getInstance(TaomuThriftTHsHaServer);
		val name = injecotr.getInstance(Key.get(String, Names.named("taomu.kademlia.name")))
		val ser = server.get(name, injecotr.getInstance(Key.get(TProcessor, Names.named("taomu.toolkit.kademlia.processor"))))
		this.context.executor.submit([ser.serve])
	}

	override init() {
		// 服务加载在这里实现
		val injector = this.context.injectorSupplier.get
		var a = injector.getInstance(ResourceCollector);
		a.init();
		injector.getInstance(ICheckRemoteNode).pingQ
		
		val gkeyHost = Key.get(String, Names.named("taomu.kademlia.peer.host"));
		val gkeyPort = Key.get(Integer, Names.named("taomu.kademlia.peer.port"));
		val gkeyKRoutingTable = Key.get(KRoutingTable)
		if (injector.getExistingBinding(gkeyHost) !== null) {
			this.context.executor.execute([
				// 加入节点
				var checkPeer = injector.getInstance(ICheckPeer)
				var host = injector.getInstance(gkeyHost)
				var port = injector.getInstance(gkeyPort)
				var peer = new KPeerNode(host, port);
				var check = checkPeer.apply(peer);
				LOG.info("建立连接:{} 成功", check)
				if (!check && injector.getExistingBinding(gkeyKRoutingTable) !== null) {
					var krt = injector.getInstance(gkeyKRoutingTable)
					KRoutingTableUtils.loadConfig(krt, checkPeer)
				}
			])
		} else if (injector.getExistingBinding(gkeyKRoutingTable) !== null) {
			LOG.info("尝试使用 Proxy 建立连接");
			var krt = injector.getInstance(gkeyKRoutingTable)
			var checkPeer = injector.getInstance(ICheckPeer)
		}
	}

}
